/**
 * Copyright (c) 2009 Robisoft, Inc. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.chalmerslosers.controllers;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.portlet.ActionResponse;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.chalmerslosers.utils.Post;
import com.liferay.portal.PortalException;
import com.liferay.portal.SystemException;
import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
import com.liferay.portal.model.User;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portlet.expando.DuplicateColumnNameException;
import com.liferay.portlet.expando.NoSuchTableException;
import com.liferay.portlet.expando.model.ExpandoColumnConstants;
import com.liferay.portlet.expando.model.ExpandoRow;
import com.liferay.portlet.expando.model.ExpandoTable;
import com.liferay.portlet.expando.model.ExpandoValue;
import com.liferay.portlet.expando.service.ExpandoColumnLocalServiceUtil;
import com.liferay.portlet.expando.service.ExpandoRowLocalServiceUtil;
import com.liferay.portlet.expando.service.ExpandoTableLocalServiceUtil;
import com.liferay.portlet.expando.service.ExpandoValueLocalServiceUtil;

@RequestMapping("VIEW")
@Controller
public class SidanWallController {
	
	private static final String NOOFPOSTS_ATTRIBUTE_NAME = "com.chalmerslosers.number.of.posts";
	private static final String INDEX_ATTRIBUTE_NAME = "com.chalmerslosers.index";
	private static String TABLE_NAME = "com.chalmerslosers.post";

	@RequestMapping
	// default renderer
	public String doView(Model model, RenderRequest request,
			RenderResponse response, PortletSession session) throws Exception {
		
		int noOfPosts=50;
		int index = 0;
		if(session.getAttribute(INDEX_ATTRIBUTE_NAME)!=null){
			index = (Integer)session.getAttribute(INDEX_ATTRIBUTE_NAME);
		} else {
			session.setAttribute(INDEX_ATTRIBUTE_NAME, index);
		}
	
		if(session.getAttribute(NOOFPOSTS_ATTRIBUTE_NAME)!=null){
			noOfPosts = (Integer) session.getAttribute(NOOFPOSTS_ATTRIBUTE_NAME);
		} else {
			session.setAttribute(NOOFPOSTS_ATTRIBUTE_NAME, noOfPosts);
		}
		
		System.out.println("noOfPosts: " + noOfPosts + " index: " + index + "\n Attributes:\n" + session.getAttributeMap());
		
		
		
		
		System.out.println(this.getClass().getCanonicalName() + ".doView(...) "
				+ request.getContextPath());
		try {
			ExpandoTableLocalServiceUtil.getTable(TABLE_NAME, TABLE_NAME);
		} catch (NoSuchTableException nste) {
			setupExpando();
		}
			
		List<Post> parentPosts = getParentPosts(index, noOfPosts);
		List<Post> childrenPosts = getChildren(parentPosts);
		List<Post> posts = getFlatListPost(index, noOfPosts);
		
		model.addAttribute("post", new Post());
		model.addAttribute("flatListPosts", posts);
		model.addAttribute("parentPosts", parentPosts);
		model.addAttribute("childPosts", childrenPosts);
		return "sidan";
	}
	
	@RequestMapping(params = "action=nextPage")
	public void next(Model model, PortletRequest req, ActionResponse response, PortletSession session) {
		System.out.println(this.getClass().getCanonicalName() + ".next(....)");	
		int noOfPosts= (Integer) session.getAttribute(NOOFPOSTS_ATTRIBUTE_NAME);
		int index = (Integer)session.getAttribute(INDEX_ATTRIBUTE_NAME);
		
		
		session.setAttribute(INDEX_ATTRIBUTE_NAME, index+noOfPosts);
		
		
	}
	
	@RequestMapping(params = "action=prevPage")
	public void prev(Model model, PortletRequest req, ActionResponse response, PortletSession session) {
		System.out.println(this.getClass().getCanonicalName() + ".next(....)");	
		int noOfPosts= (Integer) session.getAttribute(NOOFPOSTS_ATTRIBUTE_NAME);
		int index = (Integer)session.getAttribute(INDEX_ATTRIBUTE_NAME);
		
		if(index>=noOfPosts){
			session.setAttribute(INDEX_ATTRIBUTE_NAME, index-noOfPosts);
		}
		
	}

	@RequestMapping(params = "action=post")
	public void post(Model model, @ModelAttribute("post") Post post,
			PortletRequest req, ActionResponse response, PortletSession session) {
		System.out.println(this.getClass().getCanonicalName()
				+ ".post(...) Sidan post");
		System.out.println(req.getRemoteUser());

		System.out.println(post.getContent() + " " + post.getAnonAuthor() );
		
		if(!"".equals(post.getContent())){
			try{
				User user = null;
				if (req.getRemoteUser() != null && req.getRemoteUser() != "") {
					
						user = UserLocalServiceUtil.getUser(Long.parseLong(req
								.getRemoteUser()));
			
				}
		
				if (user != null) {
					
						post(post, user);
					
		
				} else {
					
						post(post);
				
				}
		
				// update time stamp
			if(post.getTopParentId()!=null && post.getTopParentId()!=0){ 
				
					
					updatePostTimeStamp(post);
					
			}
			} catch (SystemException e) {
				
				e.printStackTrace();
			} catch (PortalException e) {
	
				e.printStackTrace();
			}
			// save the actual post
			session.setAttribute(INDEX_ATTRIBUTE_NAME, 0); //Returns the user to the first screen as the post will be the topmost.
		}
	}

	private Post getPostById(long id) throws PortalException, SystemException {
//		System.out.println(this.getClass().getCanonicalName()+".getPostById("+id+")");
		ExpandoTable t = ExpandoTableLocalServiceUtil.getTable(TABLE_NAME, TABLE_NAME);
		
		ExpandoRow row = ExpandoRowLocalServiceUtil.getRow(t.getTableId(), id);
		
		return getPostFromExpandoRow(row);
	}
	


	private void updatePostTimeStamp(Post post) throws PortalException, SystemException {
		
			ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
			System.out.println(this.getClass().getCanonicalName()+".updatePostTimeStamp()");

			long modifiedDateColumnId = ExpandoColumnLocalServiceUtil.getColumn(TABLE_NAME, TABLE_NAME, "modifiedDate").getColumnId();
			System.out.println(this.getClass().getCanonicalName()+".searchParents(...) parent: " + modifiedDateColumnId);
			
			
			DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(ExpandoValue.class, classLoader)
			.add(PropertyFactoryUtil.forName("columnId").eq(modifiedDateColumnId))
			.add(PropertyFactoryUtil.forName("classPK").eq(post.getTopParentId()));

		
			
	
			getPostById(post.getTopParentId());
			
			List<Object> expandoValues = ExpandoValueLocalServiceUtil.dynamicQuery(dynamicQuery);
			
			ExpandoValue topParentsModifiedDateExpandoValue = (ExpandoValue)expandoValues.get(0);
			topParentsModifiedDateExpandoValue.setDate(new Date());
			
			ExpandoValueLocalServiceUtil.updateExpandoValue(topParentsModifiedDateExpandoValue, true);
			
	}
	
	private List<Post> getParentPosts(int index, int noOfPosts) throws PortalException, SystemException {
		System.out.println(this.getClass().getCanonicalName()+".getParentPosts(...)");
		List<Post> parentPosts = new ArrayList<Post>();
		
		
		
		List<Object> objList = searchParents(index, noOfPosts);
		
		for(Object o : objList){
			if(o instanceof ExpandoValue){
				ExpandoValue v = (ExpandoValue)o;
				parentPosts.add(getPostById(v.getClassPK()));
			}
		}
		
		
		
		return parentPosts;
	}
	
	
	
	private List<Post> getChildren(List<Post> posts)
			throws SystemException, PortalException {
		System.out.println(this.getClass().getCanonicalName()+".getChildren(...)");
		List<Post> childPosts = new ArrayList<Post>();

		for (Post p : posts) {
			if (p.getParentId() == null
					|| p.getParentId() == -1
					&& p.getId() !=null){
					
				List<Object> objList = searchChildren(p.getId());
				
				//System.out.println( "row ID:   " +r.getClassPK());
				for(Object o : objList){
					if(o instanceof ExpandoValue){
						ExpandoValue v = (ExpandoValue)o;
						childPosts.add(getPostById(v.getClassPK()));
					}
				}
				//childPosts.addAll(listOfPostsWithoutParent(subList));
				
				
				
				
			}
		}
		return childPosts;
	}

	private Post getPostFromExpandoRow(ExpandoRow r) throws SystemException,
			PortalException {
		long id = 0;
		String author;
		String content;
		Date date;
		long parentId = 0;
		long topParentId = 0;
		if (ExpandoValueLocalServiceUtil.getValue(TABLE_NAME, TABLE_NAME, "id",
				r.getClassPK()) != null) {
			id = ExpandoValueLocalServiceUtil.getValue(TABLE_NAME, TABLE_NAME,
					"id", r.getClassPK()).getLong();
		}
		if (ExpandoValueLocalServiceUtil.getValue(TABLE_NAME, TABLE_NAME,
				"author", r.getClassPK()) != null) {
			author = ExpandoValueLocalServiceUtil.getValue(TABLE_NAME,
					TABLE_NAME, "author", r.getClassPK()).getString();
		} else {
			author = "";
		}

		if (ExpandoValueLocalServiceUtil.getValue(TABLE_NAME, TABLE_NAME,
				"content", r.getClassPK()) != null) {
			content = ExpandoValueLocalServiceUtil.getValue(TABLE_NAME,
					TABLE_NAME, "content", r.getClassPK()).getString();
		} else {
			content = "";
		}

		if (ExpandoValueLocalServiceUtil.getValue(TABLE_NAME, TABLE_NAME,
				"date", r.getClassPK()) != null) {
			date = ExpandoValueLocalServiceUtil.getValue(TABLE_NAME,
					TABLE_NAME, "date", r.getClassPK()).getDate();
		} else {
			date = new Date();
		}
	
		if (ExpandoValueLocalServiceUtil.getValue(TABLE_NAME, TABLE_NAME,
				"parentId", r.getClassPK()) != null) {
			parentId = ExpandoValueLocalServiceUtil.getValue(TABLE_NAME,
					TABLE_NAME, "parentId", r.getClassPK()).getLong();
		}

		if (ExpandoValueLocalServiceUtil.getValue(TABLE_NAME, TABLE_NAME,
				"topParentId", r.getClassPK()) != null) {
			topParentId = ExpandoValueLocalServiceUtil.getValue(TABLE_NAME,
					TABLE_NAME, "topParentId", r.getClassPK()).getLong();
		}
		
		//System.out.println("new Post(" + " " + id + " " + author + " " + content + " " + date + " " + parentId + " " + topParentId + ")");
		return new Post(id, author, content, date, parentId, topParentId);
	}

	
	private List<Post> getFlatListPost(int index, int noOfPosts) throws SystemException, PortalException {
			int count = ExpandoRowLocalServiceUtil.getRowsCount(
					TABLE_NAME,
					TABLE_NAME); //count is the index of the last post
			count = count - index; //count is the index of the last post - the desired index
			List<ExpandoRow> expandoRowList = ExpandoRowLocalServiceUtil.getRows(
					TABLE_NAME,
					TABLE_NAME, 
					count>noOfPosts?count-noOfPosts:0, 
					count); //if the list contains less posts than the desired display posts the list starts from 0
			
			List<Post> posts = new ArrayList<Post>();
	
			for(ExpandoRow expandoRow : expandoRowList){
				Post p = getPostFromExpandoRow(expandoRow);
				posts.add(0,p);
				
			}
			return posts;
	}


	private void post(Post post, User user) throws SystemException,
			PortalException {

		long id = System.currentTimeMillis();

		ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME, "id", id,
				id);
		ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME, "author",
				id, user.getFirstName());
		ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
				"content", id, post.getContent());
		if (post.getDate() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME, "date",
					id, post.getDate());
			
		} else {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME, "date",
					id, new Date(id));
		}
		
		
		
		ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
				"modifiedDate", id, new Date(id));
		
		if (post.getParentId() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"parentId", id, post.getParentId());
		} else {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"parentId", id, "");
		}
		if (post.getTopParentId() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"topParentId", id, post.getTopParentId());
		} else {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"topParentId", id, "");
		}

	}

	private void post(Post post) throws SystemException, PortalException {

		long id = System.currentTimeMillis();

		ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME, "id", id,
				id);
		if (post.getAnonAuthor() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"author", id, post.getAnonAuthor());
		}
		if (post.getContent() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"content", id, post.getContent());
		}
		if (post.getDate() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME, "date",
					id, post.getDate());
			
		} else {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME, "date",
					id, new Date(id));
		}
		ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
				"modifiedDate", id, new Date(id));
		if (post.getParentId() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"parentId", id, post.getParentId());
		} else {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"parentId", id, new Long(-1));
		}
		if (post.getTopParentId() != null) {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"topParentId", id, post.getTopParentId());
		} else {
			ExpandoValueLocalServiceUtil.addValue(TABLE_NAME, TABLE_NAME,
					"topParentId", id, new Long(-1));
		}
		
	}

	protected void setupExpando() throws Exception {
		ExpandoTable table = ExpandoTableLocalServiceUtil.addTable(TABLE_NAME,
				TABLE_NAME);

		long id = table.getTableId();
		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "id",
					ExpandoColumnConstants.LONG);
		} catch (DuplicateColumnNameException dcne) {
		}

		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "author",
					ExpandoColumnConstants.STRING);
		} catch (DuplicateColumnNameException dcne) {
		}
		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "anonAuthor",
					ExpandoColumnConstants.STRING);
		} catch (DuplicateColumnNameException dcne) {
		}
		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "content",
					ExpandoColumnConstants.STRING);
		} catch (DuplicateColumnNameException dcne) {
		}
		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "date",
					ExpandoColumnConstants.DATE);
		} catch (DuplicateColumnNameException dcne) {
		}
		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "modifiedDate",
					ExpandoColumnConstants.DATE);
		} catch (DuplicateColumnNameException dcne) {
		}
		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "parentId",
					ExpandoColumnConstants.LONG);
		} catch (DuplicateColumnNameException dcne) {
		}
		try {
			ExpandoColumnLocalServiceUtil.addColumn(id, "topParentId",
					ExpandoColumnConstants.LONG);
		} catch (DuplicateColumnNameException dcne) {
		}
	}


	public  List<Object> searchChildren(Long searchId) throws PortalException, SystemException {
		ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
//		System.out.println(this.getClass().getCanonicalName()+".searchExpandoValues(" + searchId + ")");
		
		
		long topParentColumnId = -1;
		try {
			topParentColumnId = ExpandoColumnLocalServiceUtil.getColumn(TABLE_NAME, TABLE_NAME, "topParentId").getColumnId();
		} catch (SystemException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
//		System.out.println(this.getClass().getCanonicalName()+".searchExpandoValues(...) topParent: " + topParentColumnId);
		
		DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(ExpandoValue.class, classLoader)
			.add(PropertyFactoryUtil.forName("columnId").eq(topParentColumnId))
			.add(PropertyFactoryUtil.forName("data").eq(""+searchId));
		
		
		List<Object> expandoValues = ExpandoValueLocalServiceUtil.dynamicQuery(dynamicQuery);
		
		
		

		
		return expandoValues;
		

	}
	public  List<Object> searchParents(int index, int noOfPosts) throws PortalException, SystemException {
		
		
		
		
		ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
		System.out.println(this.getClass().getCanonicalName()+".searchParents()");
		
		long parentColumnId = ExpandoColumnLocalServiceUtil.getColumn(TABLE_NAME, TABLE_NAME, "parentId").getColumnId();
		System.out.println(this.getClass().getCanonicalName()+".searchParents(...) parent: " + parentColumnId);
		
		long modifiedDateColumnId = ExpandoColumnLocalServiceUtil.getColumn(TABLE_NAME, TABLE_NAME, "modifiedDate").getColumnId();
		System.out.println(this.getClass().getCanonicalName()+".searchParents(...) parent: " + modifiedDateColumnId);
		
		
		DynamicQuery topParentIdQuery = DynamicQueryFactoryUtil.forClass(ExpandoValue.class,"topParentIdColumn", classLoader);
		topParentIdQuery.setProjection(
			    ProjectionFactoryUtil.projectionList()
			    .add(ProjectionFactoryUtil.property("topParentIdColumn.classPK")));
				
		
		topParentIdQuery
			.add(PropertyFactoryUtil.forName("topParentIdColumn.columnId").eq(parentColumnId))
			.add(PropertyFactoryUtil.forName("topParentIdColumn.data").eq("-1"));
		
		DynamicQuery modifiedDateQuery = DynamicQueryFactoryUtil.forClass(ExpandoValue.class, classLoader)
		.add(PropertyFactoryUtil.forName("columnId").eq(modifiedDateColumnId))
		.add(PropertyFactoryUtil.forName("classPK").in(topParentIdQuery))
		.addOrder(PropertyFactoryUtil.forName("data").desc());
		
		
		List<Object> expandoValues = ExpandoValueLocalServiceUtil.dynamicQuery(modifiedDateQuery, index,index+noOfPosts);	
				
		return expandoValues;
	}
	
}
